﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using ADC.Comet.Core;
using Sharp.Framework.Extensions;

namespace Sharp.Framework.Comet
{
    /// <summary>
    /// Web Request管理对象
    /// </summary>
    public class RequestManagement
    {
        /// <summary>
        /// 单例实例
        /// </summary>
        private static readonly RequestManagement ObjectInstance = new RequestManagement();
        /// <summary>
        /// 单例对象
        /// </summary>
        static public RequestManagement Instance
        {
            get { return ObjectInstance; }
        }

         
        /// <summary>
        /// 请求队列
        /// </summary>
        private readonly LinkedList<AsyncRequest> _requestQueue;
        /// <summary>
        /// 日志组件
        /// </summary>
        protected FileLogger Log;
        /// <summary>
        /// 请求超时定时器
        /// </summary>
        readonly Timer _requestClreatimer;
        /// <summary>
        /// 用户状态超时定时器
        /// </summary>
        readonly Timer _userClreatimer;
        /// <summary>
        /// 用户列表
        /// </summary>
        public readonly Hashtable _users;
        /// <summary>
        /// 在线用户数量
        /// </summary>
        public int OnlineCount { get { return _users.Count; } }
        /// <summary>
        /// 请求超时 检查间隔
        /// </summary>
        const int RequestTimerPeriod = 10 * 1000;
        /// <summary>
        /// 用户登录超时 检查间隔
        /// </summary>
        const int UserTimeOutPeriod = 25 * 1000;
        /// <summary>
        /// 请求超时时间
        /// </summary>
        const int RequestTimeout = 25 * 1000;
        /// <summary>
        /// 请求超时时间
        /// </summary>
        const int UserTimeout = 60 * 1000;

        private RequestManagement()
        {
            Log = new FileLogger();
            _users = new Hashtable();  
            _requestQueue = new LinkedList<AsyncRequest>();
            _requestClreatimer = new Timer(RequestTimeOutProc);
            _requestClreatimer.Change(0, RequestTimerPeriod);
            _userClreatimer = new Timer(UserTimeOutProc);
            _userClreatimer.Change(0, UserTimeOutPeriod);
        }
        /// <summary>
        /// 用户超时处理
        /// </summary>
        /// <param name="state"></param>
        private void UserTimeOutProc(object state)
        {
            try
            {
                lock (_users)
                {
                    var list = new List<object>();
                    var user = _users.GetEnumerator();
                    while (user.MoveNext())
                    {
                        var session = user.Value as UserSession;
                        if (session == null) continue;
                        var userid = user.Key;
                        var now = DateTime.Now.GenerateTimeStamp();
                        var diff = (now - session.From);
                        if (diff <= UserTimeout) continue;
#if DEBUG
                        Log.Warn("用户超时::超时用户Id：" + userid + ", 用户最后接收消息/请求时间：" + session.From);
#endif
                        list.Add(userid);
                    }

                    foreach (var usid in list)
                    {
                        _users.Remove(usid);
                    }

                    foreach (var uid in list)
                    {
                        //发送IM用户离线通知
                        foreach (DictionaryEntry tuser in _users)
                        {
                            Send(new Message
                                     {
                                         Sender = (int) uid,
                                         Receiver = (int) tuser.Key,
                                         Command = "SendUserStatus",
                                         Content = "offline",
                                         Created = DateTime.Now.GenerateTimeStamp()
                                     });
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "用户超时处理服务");
            }
        }

        private void RequestTimeOutProc(object state)
        {
            try
            {
                var timeoutNodes = new List<AsyncRequest>();
                var now = DateTime.Now.GenerateTimeStamp();
                var n = _requestQueue.First;
                while (n != null)
                {
                    var diff = (now - n.Value.Created);
                    if (diff <= RequestTimeout) break;
                    timeoutNodes.Add(n.Value);
                    n = n.Next;
                }
                lock (_users)
                {
                    foreach (var rn in timeoutNodes)
                    {
                        _requestQueue.Remove(rn);
                        if (!_users.ContainsKey(rn.UserId)) continue;
                        var session = _users[rn.UserId] as UserSession;
                        if (session == null || session.Requests.Count == 0) continue;
                        session.Requests.Remove(rn);
                        var messages = new List<Message>
                                           {
                                               new Message(1000, rn.UserId, "TimeOut",
                                                           DateTime.Now.GenerateTimeStamp())
                                           };
                        session.From = messages.Max(m => m.Created);
#if DEBUG
                        Log.Warn("请求超时::用户Id：" + rn.UserId + ", 用户接收超时返回时间：" + session.From);
#endif
                        rn.Write(messages, session.From);
                        ThreadPool.QueueUserWorkItem(rn.Complete);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "请求超时处理服务");
            }
        }

        public void Initialize(HttpContext context)
        {

        }

        public void Dispose()
        {
        }

        /// <summary>
        /// 发送新消息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public SendStatus Send(Message message)
        {
            if (message.Command == "SendUserStatus" && message.Sender > 0)
            {
                if (_users.ContainsKey(message.Sender))
                {
                    lock (_users)
                    {
                        var tsession = _users[message.Sender] as UserSession;
                        if (tsession != null)
                        {
                            switch (message.Content as string)
                            {
                                case "online":
                                    tsession.Status = UserStatus.Online;
                                    break;
                                case "offline":
                                    tsession.Status = UserStatus.Offline;
                                    break;
                                case "busy":
                                    tsession.Status = UserStatus.Busy;
                                    break;
                                case "leave":
                                    tsession.Status = UserStatus.Leave;
                                    break;
                            }
                        }
                    }
                }
            }
            lock (_users)
            {
                if (_users.ContainsKey(message.Receiver))
                {
                    var session = _users[message.Receiver] as UserSession;
                    var removeRequests = new List<AsyncRequest>();
                    if (session != null && session.Requests.Count > 0)
                    {
                        session.From = message.Created;
#if DEBUG
                        Log.Warn("主动推送Send::用户Id：" + message.Receiver + ", 用户接收消息时间：" + session.From);
#endif
                        var messages = new List<Message> {message};
                        foreach (var request in session.Requests)
                        {
                            request.Write(messages, session.From);
                            removeRequests.Add(request);
                            ThreadPool.QueueUserWorkItem(request.Complete);
                        }
                        //移除监听器
                        foreach (var request in removeRequests)
                        {
                            _requestQueue.Remove(request);
                            session.Requests.Remove(request);
                        }
                        return SendStatus.Sucees;
                    }
                    MessageManagement.Instance.Add(message);
                    return SendStatus.CacheSend;
                }
            }
            return SendStatus.OffLine;
        }

        /// <summary>
        /// 
        /// 添加消息监听器，如果查找到符合监听器条件的消息，返回false，此时不会添加监听器 
        /// </summary> 
        /// <param name="request"></param>
        /// <returns></returns> 
        public bool Receive(AsyncRequest request)
        {
            if (!_users.ContainsKey(request.UserId))
            {
                try
                {
                    lock (_users)
                    {
                        _users.Add(request.UserId, new UserSession
                                                       {
                                                           Requests = new List<AsyncRequest>(),
                                                           IsTimeOut = false,
                                                           Status = UserStatus.Online,
                                                           From = DateTime.Now.GenerateTimeStamp()
                                                       });
                    }

                    //发送IM用户上线通知
                    foreach (var tuser in
                        _users.Cast<DictionaryEntry>().Where(u => (int) u.Key != request.UserId))
                    {
                        Send(new Message
                                 {
                                     Sender = request.UserId,
                                     Receiver = (int) tuser.Key,
                                     Command = "SendUserStatus",
                                     Content = "online",
                                     Created = DateTime.Now.GenerateTimeStamp()
                                 });
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "接收请求服务::添加用户到在线用户哈希表");
                }
            }

            lock (_users)
            {
                var session = _users[request.UserId] as UserSession;
                if (session == null)
                {
                    return true;
                }

                //查找消息
                var messages = MessageManagement.Instance.Find(request.UserId, session.From);
                session.From = DateTime.Now.GenerateTimeStamp();
#if DEBUG
                Log.Warn("主动请求Receive::用户Id：" + request.UserId + ", 用户请求时间：" + session.From);
#endif
                if (messages.Count == 0)
                {
                    //插入监听器
                    session.Requests.Add(request);
                    _requestQueue.AddLast(request);
                }
                else
                {
                    //发送消息
                    request.Write(messages, messages.Max(m => m.Created));
                    foreach (var message in messages)
                    {
                        MessageManagement.Instance.Remove(message);
                    }
                }

                return messages.Count == 0;
            }
        }

        /// <summary>
        /// 获取用户状态
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public UserStatus GetUserStatus(int userId)
        {
            if(_users.ContainsKey(userId))
            {
                var session = _users[userId] as UserSession;
                return session != null ? session.Status : UserStatus.Online;
            }
            return UserStatus.Offline;
        }
    }
}